cookie

客户端和服务器的传输使用 HTTP 协议,HTTP 协议是无状态的

无状态,就是每一次请求响应都是独立的,服务器不知道这一次请求,和之前某次请求是不是同一个人。

有什么办法能够让服务器标识出请求的身份呢?

服务器按照下面的流程来认证客户端的身份:

  1. 客户端上次请求后(如:登录成功),服务器会给客户端一个出入证
  2. 后续客户端的每次请求,都必须要附带这个出入证

服务器发扬了认证不认人的优良传统,就可以很轻松的识别身份了。

![[image-20200417161950450.png]]

但是,用户不可能只在一个网站登录,于是客户端会收到来自各个网站的出入证,因此,就要求客户端要有一个类似于卡包的东西,能够具备下面的功能:

  1. 能够存放多个出入证:这些出入证来自不同的网站,也可能是一个网站有多个出入证,分别用于出入不同的地方
  2. 能够自动出示出入证:客户端在访问不同的网站时,能够自动的把对应的出入证附带请求发送出去。
  3. 正确的出示出入证:客户端不能将肯德基的出入证发送给麦当劳。
  4. 管理出入证的有效期:客户端要能够自动的发现那些已经过期的出入证,并把它从卡包内移除。
  5. 保证出入证安全:对出入证有一定的安全保障措施。

能够满足上面所有要求的,就是 cookie,cookie 类似于一个卡包,专门用于存放各种出入证,并有着一套机制来自动管理这些证件。

cookie 是浏览器中特有的一个概念,它就像浏览器的专属卡包,管理着各个网站的身份信息。

每个 cookie 就相当于是属于某个网站的一个卡片,它记录了下面的信息:

SameSite=None 但未设置 Secure 的报错: ^b7756d

Cookie "myCookie" rejected because it has the "SameSite=None" attribute but is missing the "secure" attribute.

This Set-Cookie was blocked because it had the "SameSite=None" attribute but did not have the "Secure" attribute, which is required in order to use "SameSite=None".

当浏览器向服务器发送一个请求的时候,它会瞄一眼自己的卡包,看看哪些卡片适合附带捎给服务器

如果一个 cookie 同时满足以下条件,则这个 cookie 会被附带到请求中:

具体加入的方式是,浏览器会将符合条件的 cookie,自动放置到 Cookie 请求头中,值的格式是 key1=value1; key2=value2; ...,每一个键值对就是一个符合条件的 cookie。

cookie 中包含了重要的身份信息,永远不要把你的 cookie 泄露给别人!否则,他人就拿到了你的证件,就具备了为所欲为的可能性。

由于 cookie 是保存在浏览器端的,同时,很多证件又是服务器颁发的

所以,cookie 的设置有两种模式:

服务器可以通过设置响应头,来告诉浏览器应该如何设置 cookie,响应头按照下面的格式设置:

Set-Cookie: cookie1
Set-Cookie: cookie2

通过这种模式,就可以在一次响应中设置多个 cookie 了。其中,每个 cookie 的格式如下:

key=value; path=?; domain=?; expire=?; max-age=?; secure; httponly

每个 cookie 除了键值对是必须要设置的,其他的属性都是可选的,并且顺序不限。

当这样的响应头到达客户端后,浏览器会自动的将 cookie 保存到卡包中,如果卡包中已经存在一模一样的卡片(其他信息,如 path、domain 相同),则会自动的覆盖之前的设置。

如何删除浏览器的一个 cookie 呢?

如果要删除浏览器的 cookie,只需要让服务器响应一个同样的域、同样的路径、同样的 key,只是时间已经过期的 cookie 即可:

set-cookie: token=; domain=yuanjin.tech; path=/; max-age=-1

所以,删除 cookie 其实就是修改 cookie 让其过期。浏览器按照要求修改了 cookie 后,会发现 cookie 已经过期,于是自然就会删除了。

注意

无论是修改还是删除,都要注意 cookie 的域和路径,因为完全可能存在域或路径不同,但 key 相同的 cookie,因此无法仅通过 key 确定是哪一个 cookie

既然 cookie 是存放在浏览器端的,所以浏览器向 JS 公开了接口,让其可以设置 cookie:

document.cookie = "key=value; path=?; domain=?; expire=?; max-age=?; secure";

可以看出,在客户端设置 cookie,和服务器设置 cookie 的格式一样,只是有下面的不同:

session

原理

cookie 的数据都是存到客户端的,很不安全,session 基于 cookie 实现。

其原理就是:服务器开辟一块空间(可以是狭义的 session 内存空间,也可以是 Redis 等缓存数据库),将该用户相关的数据存储到该空间,给此空间分配一个 session id(sid)并通过 cookie 返回给客户端,下次该客户端请求服务器就会携带 sid,服务器可以通过 sid 获取空间中存储的内容

消除 session

session 会占用服务器资源,会话结束就要将其销毁,通常有两种方式:

  1. 过期时间:当客户端长时间没有传递 session id 过来时,服务器可以在过期时间之后自动清除 session
  2. 客户端主动通知:可以使用 JS 监听客户端页面关闭或其他退出操作,然后通知服务器清除 session

面试题

cookie、sessionStorage、localStorage 都是保存本地数据的方式。

cookie 用于标识请求端身份信息

HTML5 新增了 sessionStorage 和 localStorage,前者用于保存会话级别的数据,后者用于更持久的保存数据。

[[004.浏览器离线存储|浏览器离线存储]]

cookie 和 session:

  1. cookie 的数据保存在浏览器端;session 的数据保存在服务器
  2. cookie 的存储空间有限;session 的存储空间不限
  3. cookie 只能保存字符串;session 可以保存任何类型的数据
  4. cookie 中的数据容易被获取;session 中的数据难以获取
  5. session 基于 cookie,cookie 基于浏览器

token(如:[[005.JWT|JWT]]):

  1. token 将数据存到浏览器端,服务端通过验证签名防止篡改和伪造
  2. token 不基于浏览器实现
  3. token 不能放敏感信息,当然可以基于 token 实现 session 就可以在服务器放敏感信息了